package dao

import (
	"context"
	"device-admin/config/redis"
	"device-admin/internal/dal"
	"device-admin/internal/define"
	"strings"
	"time"

	"github.com/golang-module/carbon/v2"
	"gorm.io/gen/field"
	"gorm.io/gorm"
)

type DeviceActiveDuration struct{}

type DeviceDailyActiveSummary struct {
	Date  string `json:"date" gorm:"column:date"`
	Total int64  `json:"total" gorm:"column:total"`
}

// 获取每日开机设备数
func (mda DeviceActiveDuration) GetDailyOnlineDevice(
	ctx context.Context,
	query *dal.Query,
	merchantPath string, // 商户路径，多个以逗号分隔
	locationID string, // 位置id，多个以逗号分隔
	startTime, endTime int64,
) []DeviceDailyActiveSummary {
	var dailyOnlineDevice []DeviceDailyActiveSummary
	d := query.Device
	da := query.DeviceActiveDuration
	tx := da.WithContext(ctx).
		Join(d, d.RobotID.EqCol(da.RobotID)).                                        // 联表
		Select(da.ID.Count().As("total"), da.Date).                                  // 按日期统计总数
		Where(da.CreatedAt.Between(startTime, endTime)).                             // 指定时间内的设备
		Where(field.NewInt(d.TableName(), d.MerchantID.ColumnName().String()).Gt(1)) // 有效设备，已经分配商户的

	// 所属商户，Group条件
	tx = mda.WithLocationCondition(ctx, query, tx, locationID)
	// 所属位置
	tx = mda.WithMerchantCondition(ctx, query, tx, merchantPath)
	tx.Group(da.Date).Scan(&dailyOnlineDevice)
	return dailyOnlineDevice
}

// 获取每日活跃设备数
func (mda DeviceActiveDuration) GetDailyActiveDevice(
	ctx context.Context,
	query *dal.Query,
	merchantPath string,
	locationID string,
	startTime, endTime int64,
) []DeviceDailyActiveSummary {
	var dailyActiveDevice []DeviceDailyActiveSummary
	d := query.Device
	da := query.DeviceActiveDuration
	tx := da.WithContext(ctx).
		Join(d, d.RobotID.EqCol(da.RobotID)).                                        // 联表
		Select(da.ID.Count().As("total"), da.Date).                                  // 按组统计总数
		Where(da.CreatedAt.Between(startTime, endTime)).                             // 在指定时间内的
		Where(da.TaskDuration.Gt(3600 * 1000 * 6)).                                  // 每日运行里程超过360分钟的，单位为ms
		Where(field.NewInt(d.TableName(), d.MerchantID.ColumnName().String()).Gt(1)) // 有效设备，已经分配商户的

	// 所属商户，Group条件
	tx = mda.WithLocationCondition(ctx, query, tx, locationID)
	// 所属位置
	tx = mda.WithMerchantCondition(ctx, query, tx, merchantPath)
	tx.Group(da.Date).Scan(&dailyActiveDevice)
	return dailyActiveDevice
}

// 位置条件
func (mda DeviceActiveDuration) WithLocationCondition(
	ctx context.Context,
	query *dal.Query,
	tx dal.IDeviceActiveDurationDo,
	locationID string,
) dal.IDeviceActiveDurationDo {
	d := query.Device
	if locationID != "" {
		return tx.Where(d.LocationID.In(strings.Split(locationID, ",")...))
	}
	return tx
}

// 商户条件
func (mda DeviceActiveDuration) WithMerchantCondition(
	ctx context.Context,
	query *dal.Query,
	tx dal.IDeviceActiveDurationDo,
	merchantPath string,
) dal.IDeviceActiveDurationDo {
	d := query.Device
	merchantPathArr := strings.Split(merchantPath, ",")
	if len(merchantPathArr) > 0 {
		var tx1 dal.IDeviceActiveDurationDo
		daSess := query.DeviceActiveDuration.
			WithContext(ctx).
			Session(&gorm.Session{NewDB: true, Context: ctx})
		for index, path := range merchantPathArr {
			if index == 0 {
				tx1 = daSess.Where(d.MerchantPath.Like(path + "%"))
			} else {
				tx1.Or(d.MerchantPath.Like(path + "%"))
			}
		}
		return tx.Where(tx1)
	}
	return tx
}

type TaskDuration struct {
	ToTaskDuration     int64 // 出门时长
	TaskDuration       int64 // 任务时长
	ToChargingDuration int64 // 回充时长
	TaskRunCount       int64 // 任务次数
	IdleDuration       int64 // 空闲时长
	TaskOdometer       int64 // 任务里程
	ChargingDuration   int64 // 充电时长
}

// 获取任务时长
func (mda DeviceActiveDuration) Duration(ctx context.Context, robotIDs []string, date string) map[string]*TaskDuration {
	date = carbon.Parse(date).Layout("2006-1-2") // 活跃记录存的日期为2006-1-2格式，所以这里的格式需要转换
	// durationMap 用来存储每台设备的时长
	durationMap := map[string]*TaskDuration{}
	da := dal.DeviceActiveDuration
	dax := da.WithContext(ctx)
	records, _ := dax.Where(da.Date.Eq(date)).Where(da.RobotID.In(robotIDs...)).Find()
	// 每台设备的duration
	for _, record := range records {
		durationMap[record.RobotID] = &TaskDuration{
			ToTaskDuration:     record.ToTaskDuration,
			TaskDuration:       record.TaskDuration,
			ToChargingDuration: record.ToChargingDuration,
			TaskRunCount:       record.TaskRunCount,
			IdleDuration:       record.IdleDuration,
			TaskOdometer:       record.TaskOdometer,
			ChargingDuration:   record.ChargingDuration,
		}
	}
	return durationMap
}

// UpdateActiveDuration 更新活跃时长
func (mda DeviceActiveDuration) UpdateTaskActiveDuration(
	ctx context.Context,
	query *dal.Query,
	robotID string,
	date string,
) error {
	date = carbon.Parse(date).Layout("2006-1-2") // 活跃记录存的日期为2006-1-2格式，所以这里的格式需要转换
	// 运营任务统计
	totalOdometer, totalTimeDuration, totalRunCount := TaskRecord{}.SummaryTaskActiveInfo(ctx, dal.Q, robotID, date)
	// 缓存统计信息
	{
		rdb := redis.NewDB()
		rdb.Set(ctx, define.RedisDeviceTaskRecord+robotID+":"+date+":total_task_odometer", totalOdometer, time.Hour*24).Result()
		rdb.Set(ctx, define.RedisDeviceTaskRecord+robotID+":"+date+":total_task_duration", totalTimeDuration, time.Hour*24).Result()
	}
	// 回充时长
	toChargingDuration := TaskRecord{}.SummaryDuration(ctx, query, robotID, date, 2)
	// 出门时长
	toTaskDuration := TaskRecord{}.SummaryDuration(ctx, query, robotID, date, 3)
	// 保存活跃时长
	dad := query.DeviceActiveDuration
	_, err := dad.WithContext(ctx).
		Where(dad.RobotID.Eq(robotID)).
		Where(dad.Date.Eq(date)).
		UpdateSimple(
			dad.TaskOdometer.Value(totalOdometer),
			dad.TaskDuration.Value(totalTimeDuration),
			dad.TaskRunCount.Value(totalRunCount),
			dad.ToChargingDuration.Value(toChargingDuration),
			dad.ToTaskDuration.Value(toTaskDuration),
		)
	return err
}
